/**
 * 
 */
package com.hand.cloud.b2b.daos.impl;

import de.hybris.platform.basecommerce.model.site.BaseSiteModel;
import de.hybris.platform.commerceservices.enums.SalesApplication;
import de.hybris.platform.core.enums.OrderStatus;
import de.hybris.platform.core.model.c2l.CurrencyModel;
import de.hybris.platform.core.model.c2l.LanguageModel;
import de.hybris.platform.core.model.order.AbstractOrderEntryModel;
import de.hybris.platform.core.model.order.OrderEntryModel;
import de.hybris.platform.core.model.order.OrderModel;
import de.hybris.platform.core.model.order.delivery.DeliveryModeModel;
import de.hybris.platform.core.model.product.ProductModel;
import de.hybris.platform.core.model.product.UnitModel;
import de.hybris.platform.core.model.user.AddressModel;
import de.hybris.platform.core.model.user.CustomerModel;
import de.hybris.platform.order.DeliveryModeService;
import de.hybris.platform.orderprocessing.model.OrderProcessModel;
import de.hybris.platform.processengine.BusinessProcessService;
import de.hybris.platform.servicelayer.exceptions.ModelSavingException;
import de.hybris.platform.servicelayer.keygenerator.KeyGenerator;
import de.hybris.platform.servicelayer.model.ModelService;
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
import de.hybris.platform.servicelayer.search.FlexibleSearchService;
import de.hybris.platform.site.BaseSiteService;
import de.hybris.platform.store.BaseStoreModel;
import de.hybris.platform.store.services.BaseStoreService;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.hand.cloud.b2b.daos.AddressDAO;
import com.hand.cloud.b2b.daos.CustomerDAO;
import com.hand.cloud.b2b.daos.EPProductDAO;
import com.hand.cloud.b2b.daos.OrderDAO;
import com.hand.cloud.b2b.daos.ProductDAO;
import com.hand.cloud.b2b.model.EPAddressModel;
import com.hand.cloud.b2b.model.EPOrderEntryModel;
import com.hand.cloud.b2b.model.EPOrderModel;
import com.hand.cloud.b2b.model.EPProductModel;


/**
 * @author StephenWang
 * @time Jul 28, 2014 3:18:51 PM
 * 
 */
@Component(value = "orderDAO")
public class DefaultOrderDAO implements OrderDAO
{

	private static Logger LOG = Logger.getLogger(DefaultOrderDAO.class);

	private KeyGenerator keyGenerator;

	@Autowired
	private ModelService modelService;

	@Autowired
	private CustomerDAO customerDAO;

	@Autowired
	private ProductDAO productDAO;

	@Autowired
	private EPProductDAO epProductDAO;

	@Autowired
	private AddressDAO addressDAO;

	@Autowired
	private BaseSiteService baseSiteService;

	@Autowired
	private BaseStoreService baseStoreService;

	@Autowired
	private FlexibleSearchService flexibleSearchService;

	@Autowired
	private DeliveryModeService deliveryModeService;

	@Autowired
	private BusinessProcessService businessProcessService;

	/**
	 * 创建订单头
	 * 
	 * @param order
	 * @return order
	 */
	@Override
	public OrderModel createOrderHds(final EPOrderModel order)
	{
		LOG.info("--------createOrderHds----------");

		final OrderModel orderHds = this.modelService.create(OrderModel.class);

		//orderHds.setCode(generateOrderCode());
		orderHds.setCode("Order_" + new Date().getTime());

		orderHds.setComments(null);
		orderHds.setConsignments(null);

		// 选择默认的人民币
		CurrencyModel currency = this.getCurrencyByIsocode("CN", Boolean.FALSE);

		orderHds.setCurrency(currency);
		orderHds.setDate(new Date());

		AddressModel deliveryAddress = this.addressDAO.createAddress(order.getDeliveryAddress());

		orderHds.setEpOrder(order);

		orderHds.setDeliveryAddress(deliveryAddress);
		orderHds.setDeliveryCost(order.getPostFee());

		// 
		DeliveryModeModel deliveryMode = this.deliveryModeService.getDeliveryModeForCode("premium-net");

		orderHds.setDeliveryMode(deliveryMode);
		orderHds.setDeliveryStatus(null);

		orderHds.setDiscounts(null);
		orderHds.setExhaustedApprovers(null);
		orderHds.setExportStatus(null);
		orderHds.setFraudReports(null);

		orderHds.setFraudulent(null);
		orderHds.setGlobalDiscountValues(null);

		LanguageModel language = getLanguageByCode("zh");

		orderHds.setLanguage(language);
		orderHds.setLocale(Locale.CHINA.toString());

		orderHds.setNet(Boolean.TRUE);
		orderHds.setOrderScheduleCronJob(null);
		orderHds.setOrderTemplateCronJob(null);
		orderHds.setOwner(order.getOwner());

		AddressModel paymentAddress = this.addressDAO.createAddress(order.getDeliveryAddress());

		orderHds.setPaymentAddress(paymentAddress);
		orderHds.setPaymentCost(null);
		orderHds.setPaymentInfo(null);
		orderHds.setPaymentMode(null);

		orderHds.setPaymentStatus(null);
		orderHds.setPaymentTransactions(null);
		orderHds.setQuoteExpirationDate(null);
		orderHds.setReturnRequests(null);

		orderHds.setSchedulingCronJob(null);

		BaseSiteModel baseSite = this.baseSiteService.getBaseSiteForUID("powertools");

		orderHds.setSite(baseSite);
		orderHds.setStatus(OrderStatus.CHECKED_VALID);
		orderHds.setSalesApplication(SalesApplication.WEB);

		BaseStoreModel baseStore = this.baseStoreService.getBaseStoreForUid("powertools");

		orderHds.setStore(baseStore);
		orderHds.setTotalDiscounts(order.getDiscountFee());
		orderHds.setTotalPrice(order.getTotalFee());
		orderHds.setTotalTax(null);

		orderHds.setTotalTaxValues(null);
		orderHds.setUnit(null);

		CustomerModel customer = null;

		// 创建测试用户
		customer = this.customerDAO.createCustomer();

		orderHds.setUser(customer);
		orderHds.setVersionID(null);
		orderHds.setWorkflow(null);
		orderHds.setCalculated(Boolean.TRUE);

		try
		{
			this.modelService.save(orderHds);
		}
		catch (ModelSavingException e)
		{
			e.printStackTrace();
			LOG.info("--------createEPOrderHds Error!-------");
		}

		return orderHds;
	}

	/**
	 * 通过EPOrderModel创建OrderModel
	 * 
	 * @param epOrder
	 * @return
	 */
	@Override
	public OrderModel createOrder(EPOrderModel epOrder)
	{
		OrderModel order = createOrderHds(epOrder);

		List<AbstractOrderEntryModel> entries = new ArrayList<AbstractOrderEntryModel>();

		for (EPOrderEntryModel entry : epOrder.getOrderEntries())
		{
			OrderEntryModel orderEntry = createOrderEntry(order, entry);
			entries.add(orderEntry);
		}

		order.setEntries(entries);

		this.modelService.save(order);

		// 启动OMS process
		startProcess(order, "oms-submitorder-process");

		return order;
	}


	@Override
	public OrderModel createOrder()
	{
		LOG.info("--------createOrder------");
		OrderModel order = null;

		EPOrderModel epOrder = new EPOrderModel();

		epOrder.setInvoiceName("孤独的飞鸟");
		epOrder.setBuyerAlipayNo("stephwenWang");
		epOrder.setCreationtime(new Date());
		epOrder.setDiscountFee(null);
		epOrder.setHasPostFee(Boolean.FALSE);
		epOrder.setInvoiceType("个人发票");
		epOrder.setPayment(new Double(1000));
		epOrder.setPointFee(null);
		epOrder.setPostFee(new Double(20));
		epOrder.setTotalFee(new Double(1020));

		EPAddressModel address = new EPAddressModel();

		address.setReceiverAddress("pudong");
		address.setReceiverCity("SH");
		address.setReceiverDistrict("Pudong");
		address.setReceiverMobile("1234567");
		address.setReceiverName("hello");
		address.setReceiverState("SH");
		address.setReceiverZip("210210");

		epOrder.setDeliveryAddress(address);
		epOrder.setPaymentAddress(address);

		order = createOrderHds(epOrder);

		LOG.info("order_code:" + order.getCode());
		LOG.info("order_pk:" + order.getPk());

		ProductModel product = this.productDAO.getProductByCode("637227");

		try
		{
			// 测试新增EPProductModel
			EPProductModel epProduct = this.epProductDAO.createEPProduct(product);
			LOG.info("EPProduct_PK:" + epProduct.getPk());
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}

		//		EPOrderEntryModel orderEntry = new EPOrderEntryModel();
		//
		//		orderEntry.setProduct(product);
		//		orderEntry.setNum(new Long(2));
		//		orderEntry.setOid("EP_09132412");
		//		orderEntry.setOrder(epOrder);
		//		orderEntry.setSku_id("EP_412341243123");
		//		orderEntry.setTotal_fee(new Double(333));

		for (EPOrderEntryModel entry : epOrder.getOrderEntries())
		{
			createOrderEntry(order, entry);
		}

		this.modelService.save(order);



		return order;
	}

	/**
	 * create order line.
	 * 
	 * @param orderHds
	 *           订单头信息
	 * @param line
	 *           订单行信息
	 * @return orderEntry
	 */
	public OrderEntryModel createOrderEntry(OrderModel order, final EPOrderEntryModel line)
	{

		LOG.info("--------createOrderEntry----------");

		final OrderEntryModel orderLns = this.modelService.create(OrderEntryModel.class);

		orderLns.setOrder(order);

		orderLns.setProduct(line.getProduct());
		orderLns.setQuantity(line.getNum());
		orderLns.setBasePrice(line.getTotalFee());
		orderLns.setTotalPrice(line.getTotalFee());

		orderLns.setCalculated(Boolean.TRUE);
		orderLns.setChosenVendor(null);
		orderLns.setComments(line.getComments());

		orderLns.setConsignmentEntries(null);
		orderLns.setCostCenter(null);
		orderLns.setDeliveryAddress(null);
		orderLns.setDeliveryMode(null);

		orderLns.setDeliveryPointOfService(null);
		orderLns.setDiscountValues(null);
		orderLns.setEntryNumber(null);
		orderLns.setGiveAway(Boolean.FALSE);

		orderLns.setInfo(null);
		orderLns.setNamedDeliveryDate(null);
		orderLns.setOwner(line.getOwner());
		orderLns.setQuantityStatus(null);

		orderLns.setRejected(Boolean.FALSE);
		orderLns.setTaxValues(null);

		UnitModel unit = getUnitByCode("pieces");

		orderLns.setUnit(unit);

		try
		{
			this.modelService.save(orderLns);
		}
		catch (final Exception e)
		{
			e.printStackTrace();
			LOG.info("----------createOrderEntry ERROR!-----------");
		}
		return orderLns;
	}

	/**
	 * 通过isoCode获取语言
	 * 
	 * @param string
	 * @return
	 */
	public LanguageModel getLanguageByCode(String isoCode)
	{
		LanguageModel language = new LanguageModel();

		language.setActive(Boolean.TRUE);
		language.setIsocode(isoCode);

		try
		{
			language = this.flexibleSearchService.getModelByExample(language);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}

		return language;
	}


	/**
	 * 通过计量单位的code获取对应的计量单位
	 * 
	 * @return
	 */
	private UnitModel getUnitByCode(String code)
	{
		UnitModel unit = this.modelService.create(UnitModel.class);
		unit.setCode(code);

		try
		{
			unit = this.flexibleSearchService.getModelByExample(unit);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
		return unit;
	}

	/**
	 * 通过isocode编码获取货币
	 * 
	 * @return
	 */
	private CurrencyModel getCurrencyByIsocode(String isocode, Boolean base)
	{

		CurrencyModel currency = this.modelService.create(CurrencyModel.class);
		currency.setIsocode(isocode);
		currency.setActive(Boolean.TRUE);
		currency.setBase(base);

		try
		{
			currency = this.flexibleSearchService.getModelByExample(currency);
			LOG.info("-----currency_pk:" + currency.getPk());
		}
		catch (Exception e)
		{
			e.printStackTrace();
			LOG.info("--------getCurrencyByIsocode Error!-------");
			return null;
		}
		return currency;
	}

	/**
	 * 创建订单号。
	 * 
	 * @return str
	 */
	@Override
	public String generateOrderCode()
	{
		final Object generatedValue = keyGenerator.generate();
		if (generatedValue instanceof String)
		{
			return (String) generatedValue;
		}
		else
		{
			return String.valueOf(generatedValue);
		}
	}

	/**
	 * @return the keyGenerator
	 */
	public KeyGenerator getKeyGenerator()
	{
		return keyGenerator;
	}

	/**
	 * @param keyGenerator
	 *           the keyGenerator to set
	 */
	public void setKeyGenerator(final KeyGenerator keyGenerator)
	{
		this.keyGenerator = keyGenerator;
	}


	/**
	 * 得到所有已完成的所有订单
	 * 
	 * @return List<Object>
	 */
	@Override
	public List<Object> getCompletedOrders()
	{
		List<Object> list = new ArrayList<Object>();

		StringBuffer queryStr = new StringBuffer("");
		queryStr.append("select {p.pk} ").append("from {order as p join orderstatus as s on {p.status}={s.pk}}")
				.append(" where {s.code} = 'COMPLETED'");

		FlexibleSearchQuery query = new FlexibleSearchQuery(queryStr.toString());
		LOG.info("----queryStr:" + query.getQuery());

		try
		{
			list = this.flexibleSearchService.search(query).getResult();
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
		return list;
	}

	@Override
	public void deleteOrder(String pk)
	{
		modelService.remove(pk);
		LOG.info("--------delete order success------" + pk.toString());
	}

	@Override
	public void modifyOrder(EPOrderModel epOrder)
	{
		LOG.info("--------modifyOrder------");
		OrderModel orderModel = new OrderModel();
		try
		{
			BeanUtils.copyProperties(orderModel, epOrder);
		}
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
			LOG.info("-------modifyOrder order error -----");
		}
		catch (InvocationTargetException e)
		{
			e.printStackTrace();
			LOG.info("-------modifyOrder order error -----");
		}
		modelService.save(orderModel);
		LOG.info("-------modifyOrder order success -----");

	}

	/**
	 * 启动订单流程
	 * 
	 * @param orderModel
	 */
	public void startProcess(final OrderModel orderModel, final String orderProcessCode)
	{
		LOG.info("--------------startProcess------------");
		final OrderModel order = orderModel;
		final BaseStoreModel store = order.getStore();
		//		final String orderProcessCode = store.getSubmitOrderProcessCode();

		if (orderProcessCode == null || orderProcessCode.isEmpty())
		{
			LOG.error("~~~~~~~~~~~~~~~~~~~~~~>>>>>>>>>>>>>>>>>>>>>Unable to start fulfilment process for order [" + order.getCode()
					+ "]. Store [" + store.getUid() + "] has missing SubmitOrderProcessCode");
		}
		else
		{
			final String processCode = orderProcessCode + order.getCode() + System.currentTimeMillis();
			final OrderProcessModel businessProcessModel = (OrderProcessModel) this.businessProcessService.createProcess(
					processCode, orderProcessCode);

			businessProcessModel.setOrder(order);
			this.modelService.save(businessProcessModel);
			this.businessProcessService.startProcess(businessProcessModel);
		}
	}
}
